package cn.b.sky.shop.activiti.service.impl;

import cn.b.sky.shop.activiti.constans.GlobalDefine;
import cn.b.sky.shop.activiti.dao.WaitTaskDao;
import cn.b.sky.shop.activiti.dao.WorkFlowHistoryDao;
import cn.b.sky.shop.activiti.enums.FlowNodeUserEnum;
import cn.b.sky.shop.activiti.enums.ProcessInstanceStatusEnum;
import cn.b.sky.shop.activiti.model.*;
import cn.b.sky.shop.activiti.model.condition.WaitTaskCondition;
import cn.b.sky.shop.activiti.service.CustomGroupAndRoleService;
import cn.b.sky.shop.activiti.service.DeploymentNodeService;
import cn.b.sky.shop.activiti.service.WorkFlowFacade;
import cn.b.sky.shop.activiti.utils.CustomProcessDiagramGenerator;
import cn.b.sky.common.constants.SystemConstant;
import cn.b.sky.common.exception.ImeException;
import cn.b.sky.common.model.Page;
import cn.b.sky.common.utils.DateUtils;
import cn.b.sky.form.service.FormObjectService;
import cn.b.sky.user.service.UserService;
import cn.b.sky.user.service.model.UserInfo;
import org.activiti.bpmn.model.*;
import org.activiti.engine.*;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.impl.cmd.GetBpmnModelCmd;
import org.activiti.engine.impl.interceptor.Command;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.runtime.Execution;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.awt.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Service("workFlowFacade")
public class WorkFlowFacadeImpl implements WorkFlowFacade {

  private static final Logger LOGGER = LoggerFactory.getLogger(WorkFlowFacadeImpl.class);

  private static final int MIN_X = 5;

  @Autowired
  private RuntimeService runtimeService;

  @Autowired
  private IdentityService identityService;

  @Autowired
  private RepositoryService repositoryService;

  @Autowired
  private TaskService taskService;

  @Resource
  private ManagementService managementService;

  @Autowired
  private HistoryService historyService;

  @Autowired
  private WorkFlowHistoryDao workFlowHistoryDao;

  @Autowired
  private WaitTaskDao waitTaskDao;

  @Resource
  private DeploymentNodeService deploymentNodeService;

  @Resource
  private CustomGroupAndRoleService customGroupAndRoleService;

  @Resource
  private FormObjectService formObjectService;

  @Resource
  private UserService userService;

  @Override
  public ProcessInstance startProcess(Map<String, Map<String, Object>> map) {
    Map<String, Object> operationMap = map.get(GlobalDefine.WorkFlow.OPERATIONMAP);
    Map<String, Object> flowMap = map.get(GlobalDefine.WorkFlow.WORKFLOWMAP);
    //流程定义id启动流程
    String flowDefinitionId = flowMap.get(GlobalDefine.WorkFlow.PROCESSDEFINITIONID) == null ? null : flowMap.get(
        GlobalDefine.WorkFlow.PROCESSDEFINITIONID).toString();
    String flowDefinitionKey = flowMap.get(GlobalDefine.WorkFlow.PROCESSDEFINITIONKEY) == null ? null : flowMap.get(
        GlobalDefine.WorkFlow.PROCESSDEFINITIONKEY).toString();
    String tenantId = (String) operationMap.get(GlobalDefine.WorkFlow.CUREENTSITECODE);
    String businessKey = operationMap.get(GlobalDefine.WorkFlow.BUSINESSKEY) == null ? null : operationMap.get(
        GlobalDefine.WorkFlow.BUSINESSKEY).toString();
    String formKey = flowMap.get(GlobalDefine.WorkFlow.FORMKEY) == null ? null : flowMap.get(
        GlobalDefine.WorkFlow.FORMKEY).toString();
    //校验流程启动的必要条件
    checkStartProcessCondition(flowDefinitionId, flowDefinitionKey, businessKey, formKey);
    if (!StringUtils.isBlank(flowDefinitionId) || !StringUtils.isBlank(flowDefinitionKey)) {
      // 用来设置启动流程的人员ID，引擎会自动把用户ID保存到activiti:initiator中
      identityService.setAuthenticatedUserId((String) operationMap.get(GlobalDefine.WorkFlow.HANDLEUSERCODE));
      ProcessInstance processInstance = null;
      if (StringUtils.isBlank(businessKey)) {//启动流程表单还没保存数据，所以这里先进行保存
        try {
          businessKey = formObjectService.saveFormObjectData(operationMap, formKey, tenantId);
          for (Map.Entry<String, Object> entry : operationMap.entrySet()) {
            flowMap.put(entry.getKey(), entry.getValue());
          }
          //启动流程
          operationMap.put(GlobalDefine.WorkFlow.BUSINESSKEY, businessKey);
        } catch (Exception e) {
          LOGGER.error("保存表单对象失败" + formKey, e);
          throw ImeException.newException("保存表单对象失败" + formKey, e);
        }
      }
      flowMap.put(GlobalDefine.WorkFlow.OPERATIONMAP, operationMap);
      if (!StringUtils.isBlank(flowDefinitionId)) {//直接启动此流程实例
        processInstance = runtimeService.startProcessInstanceById(flowDefinitionId, businessKey, flowMap);
      } else if (!StringUtils.isBlank(flowDefinitionKey)) {//启动此流程实例最新版本
        processInstance = runtimeService.startProcessInstanceByKeyAndTenantId(flowDefinitionKey, businessKey, flowMap,
            tenantId);
      }
      // 保存流程历史 
      WorkFlowHistory history = new WorkFlowHistory();
      history.setBusinessKey(processInstance.getBusinessKey());
      history.setTenantId(tenantId);
      history.setProcessInstanceId(processInstance.getId());
      history.setCheckTime(new Date());
      history.setTaskDefineKey("START");
      history.setTaskName("发起流程");
      if (flowMap.get(GlobalDefine.WorkFlow.SUGGESTION) != null) {
        history.setSuggestion(flowMap.get(GlobalDefine.WorkFlow.SUGGESTION).toString());
      }
      history.setUserText((String) operationMap.get(GlobalDefine.WorkFlow.HANDLEUSERTEXT));
      history.setUserCode((String) operationMap.get(GlobalDefine.WorkFlow.HANDLEUSERCODE));
      history.setResult("成功发起流程!");
      this.saveWorkFlowHistory(history);
      //发起流程进入已办事项
      WaitTask waitTask = new WaitTask();
      waitTask.setTaskId(GlobalDefine.WorkFlow.STARTPROCESS);
      waitTask.setAssignee((String) operationMap.get(GlobalDefine.WorkFlow.HANDLEUSERCODE));
      waitTask.setStartor((String) operationMap.get(GlobalDefine.WorkFlow.HANDLEUSERCODE));
      waitTask.setEndTime(new Date());
      waitTask.setProcessInstanceId(processInstance.getId());
      waitTask.setTenantId(tenantId);
      waitTask.setTaskName("发起流程");
      //已办
      waitTask.setStatus(1);
      ExecutionEntity execution = (ExecutionEntity) processInstance;
      waitTask.setProcessDefineName(execution.getProcessDefinition().getName());
      ProcessDefinitionEntity pde = (ProcessDefinitionEntity) execution.getProcessDefinition();
      waitTask.setVersion(pde.getVersion() + "");
      waitTask.setBusinessKey(processInstance.getBusinessKey());
      waitTaskDao.insertWaitTask(waitTask);
      return processInstance;
    } else {
      throw ImeException.newException("流程key或流程ID为空"); // 流程key为null
    }
  }

  private void checkStartProcessCondition(String flowDefinitionId,
      String flowDefinitionKey, String businessKey,String formKey) {
    if (StringUtils.isBlank(flowDefinitionId) && StringUtils.isBlank(flowDefinitionKey)) {
      throw ImeException.newException("缺少流程发起的流程定义key或者id");
    }
    if (StringUtils.isBlank(businessKey) && StringUtils.isBlank(formKey)) {
      throw ImeException.newException("缺少流程发起的业务key或者formKey");
    }
  }

  private void saveWorkFlowHistory(WorkFlowHistory history) {
    if (history == null) {
      return;
    }
    workFlowHistoryDao.insertWorkFlowHistory(history);

  }

  @Override
  public void claimTask(String taskId, String userId, String siteCode) {
    if (taskId != null) {
      taskService.claim(taskId, userId);
      WaitTask waitTask = new WaitTask();
      waitTask.setAssignee(userId);
      waitTask.setTaskId(taskId); 
      waitTask.setTenantId(siteCode);
      waitTaskDao.updateWaitTask(waitTask);
      }
  }

  @Override
  public Task getTaskById(String taskId) {
    if (StringUtils.isBlank(taskId)) {
      return null;
    }
    return taskService.createTaskQuery().taskId(taskId).singleResult();
  }

  @Override
  public ProcessInstance getProcessInstanceById(String processInstanceId) {
    if (!StringUtils.isBlank(processInstanceId)) {
      return runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
    } else {
      return null;
    }
  }

  @Override
  public String getTaskFormKey(String deploymentId, String taskDefinitionKey, String tenantId) {
    DeploymentNode deploymentNode = deploymentNodeService.getFlowNodeByDeploymentIdAndActivitId(deploymentId,
        taskDefinitionKey, tenantId);
    return deploymentNode == null ? null : deploymentNode.getFormKey();
  }

  @Override
  public String getStartNodeFormKey(String deploymentId, String tenantId) {

    return deploymentNodeService.getStartEventFormKey(deploymentId, tenantId);
  }

  @Override
  public void completeTask(String taskId, Map<String, Object> flowMap, Map<String, Object> operationMap) {
    flowMap.put(GlobalDefine.WorkFlow.OPERATIONMAP, operationMap);
    // 完成任务时触发一个event
    // 在event 中去处理业务逻辑
    /**
     * 1.监听任务从operationMap中获取数据处理业务 operationMap =
     * task.getVariable(GlobalDefine.WorkFlow.OPERATIONMAP);
     * 2.移除operationMap
     * task.removeVariable(GlobalDefine.WorkFlow.OPERATIONMAP);
     * 3.设置流转条件，为流转条件流程变量赋值 4.如果下个节点是自定义的处理人，需要为下个节点设置自定义处理人
     */
    Task task = this.getTaskById(taskId);
    this.taskService.complete(taskId, flowMap);
    WorkFlowHistory history = new WorkFlowHistory();
    history.setUserCode((String) operationMap.get(GlobalDefine.WorkFlow.HANDLEUSERCODE));
    history.setUserText((String) operationMap.get(GlobalDefine.WorkFlow.HANDLEUSERTEXT));
    history.setBusinessKey((String) operationMap.get(GlobalDefine.WorkFlow.BUSINESSKEY));
    history.setSuggestion((String) flowMap.get(GlobalDefine.WorkFlow.SUGGESTION));
    history.setTenantId(task.getTenantId());
    String result = (String) flowMap.get(GlobalDefine.WorkFlow.AUDITPARAM);
    if (StringUtils.isBlank(result)) {
      result = "0".equals(result) ? "通过" : "不通过";
    }
    history.setResult(result);
    this.saveWorkFlowHistory(task, history, null);
    //待办变已办
    WaitTask waitTask = new WaitTask();
    waitTask.setAssignee(history.getUserCode());
    waitTask.setEndTime(new Date());
    waitTask.setTaskId(task.getId());
    waitTask.setStatus(1);
    waitTask.setProcessInstanceId(task.getProcessInstanceId());
    waitTask.setTenantId(task.getTenantId());
    waitTaskDao.updateWaitTask(waitTask);
  }

  /**
   * 流程跟踪图
   * 
   * @param processInstanceId
   *            流程实例ID
   * @return 封装了各种节点信息
   */
  @Override
  public List<NodeDTO> traceProcess(String processInstanceId) {

    HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
        .processInstanceId(processInstanceId).singleResult();
    ProcessDefinition definition = repositoryService.createProcessDefinitionQuery()
        .processDefinitionId(historicProcessInstance.getProcessDefinitionId()).singleResult();
    GetBpmnModelCmd getBpmnModelCmd = new GetBpmnModelCmd(historicProcessInstance.getProcessDefinitionId());
    BpmnModel bpmnModel = managementService.executeCommand(getBpmnModelCmd);
    // 获取最大，最小的坐标，模型生成的图片坐标有失真
    Point point = CustomProcessDiagramGenerator.getMinXAndMinY(bpmnModel);
    int minX = point.x;
    int minY = point.y;
    minX = (minX <= MIN_X) ? MIN_X : minX;
    minY = (minY <= MIN_X) ? MIN_X : minY;
    minX -= MIN_X;
    minY -= MIN_X;
    Map<String, GraphicInfo> graphicInfoMap = bpmnModel.getLocationMap();

    List<NodeDTO> nodeDtos = new ArrayList<NodeDTO>();

    for (Map.Entry<String, GraphicInfo> entry : graphicInfoMap.entrySet()) {
      String key = entry.getKey();
      GraphicInfo graphicInfo = entry.getValue();
      graphicInfo.setX(graphicInfo.getX() - minX);
      graphicInfo.setY(graphicInfo.getY() - minY);
      FlowElement flowElement = bpmnModel.getFlowElement(key);
      if (flowElement instanceof ExclusiveGateway) {
        continue;
      }
      NodeDTO dto = this.convertNodeDto(graphicInfo, flowElement, key);
      if (dto != null && "USERTASK".equals(dto.getType())) {
        List<WorkFlowHistory> history = this.getWorkFlowHistoryByBusinessKeyAndTaskDefKey(
            historicProcessInstance.getBusinessKey(), flowElement.getId(), definition.getTenantId());
        dto.setHistory(history);
        //转换人员，组织和角色，显示名称
        this.setNodeDtoUserText(definition.getDeploymentId(), flowElement.getId(), definition.getTenantId(), dto);
      }
      nodeDtos.add(dto);

    }

    return nodeDtos;
  }

  private void setNodeDtoUserText(String deployMentId, String flowId, String tenantId, NodeDTO dto) {
    DeploymentNode deploymentNode = deploymentNodeService.getFlowNodeByDeploymentIdAndActivitId(deployMentId, flowId,
        tenantId);
    if (deploymentNode != null && deploymentNode.getId() != null) {
      List<FlowNodeUser> users = deploymentNodeService.getFlowNodeUserByDeploymentNodeId(deploymentNode.getId());
      for (FlowNodeUser userNode : users) {
        String value = userNode.getValue();
        if (FlowNodeUserEnum.ASSIGNEE.getCode().equals(userNode.getType())) {
          dto.setAssigneeName(value);
          if (value.indexOf("${") == -1) {
            UserInfo userInfo = userService.selectUser(deploymentNode.getTenantId(), userNode.getValue());
            if (userInfo != null) {
              dto.setAssigneeName(userInfo.getUserText());
            }
          }
        } else if (FlowNodeUserEnum.CANDIDATEGROUPS.getCode().equals(userNode.getType())) {
          dto.setGroups(userNode.getValue());

          if (!StringUtils.isBlank(value) && value.indexOf("${") == -1) {
            String groupText = customGroupAndRoleService.findGroupsTextByCode(value, deploymentNode.getTenantId());
            if (!StringUtils.isBlank(groupText)) {
              dto.setGroups(groupText);
            }
            String roleText = customGroupAndRoleService.findRolesTextByCode(value, deploymentNode.getTenantId());
            if (!StringUtils.isBlank(roleText)) {
              dto.setRoles(roleText);
            }
          }
        } else if (FlowNodeUserEnum.CANDIDATEUSERS.getCode().equals(userNode.getType())) {
          dto.setAssignee(userNode.getValue());
          if (!StringUtils.isBlank(value) && value.indexOf("${") == -1) {
            String userText = customGroupAndRoleService.findUsersTextByCode(value, deploymentNode.getTenantId());
            dto.setAssigneeName(userText);
          }
        }
      }
    }
  }

  private NodeDTO convertNodeDto(GraphicInfo graphicInfo, FlowElement flowElement, String id) {
    NodeDTO nodeDto = new NodeDTO();
    nodeDto.setX((int) graphicInfo.getX());
    nodeDto.setY((int) graphicInfo.getY());
    nodeDto.setWidth((int) graphicInfo.getWidth());
    nodeDto.setHeight((int) graphicInfo.getHeight());
    //
    nodeDto.setId(id);
    nodeDto.setName(flowElement.getName());
    if (flowElement instanceof UserTask) {
      nodeDto.setType("USERTASK");
    } else if (flowElement instanceof StartEvent) {
      nodeDto.setType("START");
    } else if (flowElement instanceof EndEvent) {
      nodeDto.setType("END");
    } else if (flowElement instanceof ExclusiveGateway) {
      nodeDto.setType("ExclusiveGateway");
    }
    return nodeDto;
  }

  @Override
  public void endWorkFlow(String processInstanceId) {
    if (!StringUtils.isBlank(processInstanceId)) {
      runtimeService.deleteProcessInstance(processInstanceId, null);
    }
  }

  @Override
  public void transferAssignee(String taskId, String userCode) {
    taskService.setAssignee(taskId, userCode);

  }

  @Override
  public void saveWorkFlowHistory(Task task, WorkFlowHistory history, String userName) {
    if (task == null || StringUtils.isBlank(task.getId())) {
      return;
    }
    HistoricTaskInstance historyInstance = historyService.createHistoricTaskInstanceQuery().taskId(task.getId())
        .singleResult();
    // 获取接收时间
    Date claimDate = historyInstance.getClaimTime();
    if (claimDate == null) {
      claimDate = historyInstance.getStartTime();
    }
    history.setCheckTime(new Date());
    // 用时，时分秒
    history.setUseTime(DateUtils.getDateUtils().getHSMStrByTwoDate(claimDate, history.getCheckTime()));
    history.setProcessInstanceId(historyInstance.getProcessInstanceId());
    HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
        .processInstanceId(historyInstance.getProcessInstanceId()).singleResult();
    if (historicProcessInstance != null) {
      //父流程id
      history.setParentProcessInstanceId(historicProcessInstance.getSuperProcessInstanceId());
    }

    history.setTaskDefineKey(task.getTaskDefinitionKey());
    history.setTaskName(task.getName());
    if (!StringUtils.isBlank(userName)) {
      history.setResult("移交：" + userName); // 移交
    } else {// 正常的处理
            // 获取当前业务id生产的任务，就是上个节点的处理结果
      String result = history.getResult();
      List<ProcessInstance> processInstances = runtimeService.createProcessInstanceQuery()
          .processDefinitionId(task.getProcessDefinitionId()).processInstanceBusinessKey(history.getBusinessKey())
          .list();
      if (processInstances.isEmpty()) {
        history.setResult("结果：" + result + "流程结束");
      } else {
        String taskName = "流向:";
        for (ProcessInstance p : processInstances) {
          //子流程或者并行或者包含
          List<Execution> childrens = runtimeService.createExecutionQuery().parentId(p.getId()).list();
          if (!childrens.isEmpty()) {
            for (Execution exe : childrens) {
              Task t = taskService.createTaskQuery().processInstanceId(exe.getProcessInstanceId())
                  .taskDefinitionKey(exe.getActivityId()).singleResult();
              if (t != null) {
                taskName += t.getName();
              }
            }
          } else {
            Task t = taskService.createTaskQuery().processInstanceId(p.getProcessInstanceId())
                .taskDefinitionKey(p.getActivityId()).singleResult();
            if (t != null) {
              taskName += t.getName();
            }
          }
        }
        history.setResult("结果：" + taskName);
      }
    }

    this.saveWorkFlowHistory(history);
  }

  @Override
  public <T> T executeCommand(Command<T> command) {
    return managementService.executeCommand(command);
  }

  @Override
  public Page findTasks(String userId, String tenantId, WaitTaskCondition page) {
    List<String> candidateGroups = customGroupAndRoleService.findGroupsAndRolesStrByUser(userId, tenantId);
    // 根据当前人的ID查询
   /* TaskQuery taskQuery = taskService.createTaskQuery().taskTenantId(tenantId);
    if (!StringUtils.isBlank(page.getProcessDefineName())) {
      taskQuery.processDefinitionNameLike(page.getProcessDefineName());
    }
    if (!StringUtils.isBlank(page.getBusinessKey())) {
      taskQuery.processInstanceBusinessKeyLikeIgnoreCase(page.getBusinessKey());
    }
    List<Task> tasks = taskQuery.or().taskCandidateOrAssigned(userId).taskCandidateGroupIn(candidateGroups)
        .listPage(page.getStartRow() - 1, page.getEndRow() - 1);
    List<WaitTask> waitTasks = new ArrayList<WaitTask>();
    for (Task task : tasks) {
      WaitTask waitTask = new WaitTask();
      waitTask.setTaskId(task.getId());
      waitTask.setAssignee(task.getAssignee());
      waitTask.setCreateTime(task.getCreateTime());
      waitTask.setTaskName(task.getName());
      ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
          .processInstanceId(task.getProcessInstanceId()).active().singleResult();
      HistoricProcessInstance his = historyService.createHistoricProcessInstanceQuery()
          .processInstanceId(task.getProcessInstanceId()).singleResult();
      String startor = his.getStartUserId();
      UserInfo user = userService.selectUser(tenantId, startor);
      waitTask.setStartor(user.getUserText());
      waitTask.setBusinessKey(his.getBusinessKey());
      ProcessDefinition pd = repositoryService.createProcessDefinitionQuery()
          .processDefinitionId(task.getProcessDefinitionId()).singleResult();
      waitTask.setProcessDefineName(pd.getName());
      waitTask.setSuspended(processInstance.isSuspended());
      waitTask.setVersion(pd.getVersion() + "");
      waitTasks.add(waitTask);
    }
    page.setTotalCount(taskQuery.count());
    page.setData(waitTasks);*/
    page.setAssignee(userId);
    page.setGroups(candidateGroups);
    page.setCandidateUsers(SystemConstant.LABLE_SPLIT + userId + SystemConstant.LABLE_SPLIT);
    page.setTenantId(tenantId);
    //待办
    page.setStatus(0);
    List<WaitTask> waitTasks = waitTaskDao.selectWaitingTaskByCondition(page);
    int count = waitTaskDao.selectWaitingTaskCountByCondition(page);
    page.setTotalCount(count);
    page.setData(waitTasks);

    return page;
  }

  @Override
  public Page findfinishedTasks(String userCode, String siteCode, WaitTaskCondition page) {
    page.setAssignee(userCode);
    page.setTenantId(siteCode);
    //已办
    page.setStatus(1);
    List<WaitTask> waitTasks = waitTaskDao.selectWaitTaskByCondition(page);
    int count = waitTaskDao.selectWaitTaskCountByCondition(page);
    page.setTotalCount(count);
    page.setData(waitTasks);
    return page;
  }

  @Override
  public Page findRunningTasks(String siteCode, WaitTaskCondition page) {
    if (StringUtils.isBlank(siteCode)) {
      return page;
    }
    //运行中，存在待办
    page.setStatus(0);
    page.setSiteCode(siteCode);
    List<WaitTask> waitTasks = waitTaskDao.selectProcessInstanceByCondition(page);
    int count = waitTaskDao.selectProcessInstanceCountByCondition(page);
    page.setTotalCount(count);
    page.setData(waitTasks);
    return page;
  }

  @Override
  public List<WorkFlowHistory> getWorkFlowHistoryByBusinessKeyAndTaskDefKey(String businessKey,
      String taskDefinitionKey, String tenantId) {
    if (StringUtils.isBlank(taskDefinitionKey)) {
      return workFlowHistoryDao.selectWorkFlowHistoryByBusinessKey(businessKey, tenantId);
    }

    return workFlowHistoryDao.selectWorkFlowHistoryByBusinessKeyAndTaskDefineKey(businessKey, taskDefinitionKey,
        tenantId);
  }

  @Override
  public List<WorkFlowHistory> getWorkFlowHistoryByprocessInstanceId(String processInstanceId, String tenantId) {
    return workFlowHistoryDao.selectWorkFlowHistoryByProcessInstanceId(processInstanceId, tenantId);
  }

  @Override
  public HistoricTaskInstance getHistoricTaskById(String taskId) {
    if (StringUtils.isBlank(taskId)) {
      return null;
    }
    return historyService.createHistoricTaskInstanceQuery().taskId(taskId).singleResult();
  }

  @Override
  public String getProcessInstanceStatus(String businessKey, String tenantId) {
    if (StringUtils.isBlank(businessKey)) {
      return ProcessInstanceStatusEnum.NOTSTART.getValue();
    }
    if (StringUtils.isBlank(tenantId)) {
      throw ImeException.newException("siteCodeIsNull.M");
    }
    List<Task> task = taskService.createTaskQuery().taskTenantId(tenantId).processInstanceBusinessKey(businessKey)
        .list();
    if (!task.isEmpty()) {
      return ProcessInstanceStatusEnum.INPROGRESS.getValue();
    } else {
      List<HistoricTaskInstance> historicTaskInstances = historyService.createHistoricTaskInstanceQuery()
          .taskTenantId(tenantId).processInstanceBusinessKey(businessKey).orderByHistoricTaskInstanceEndTime().desc()
          .list();
      if (!historicTaskInstances.isEmpty()) {
        HistoricTaskInstance his = historicTaskInstances.get(0);
        if (StringUtils.isBlank(his.getDeleteReason()) && "ACTIVITI_DELETED".equals(his.getDeleteReason())) {
          return ProcessInstanceStatusEnum.END.getValue();
        } else {
          return ProcessInstanceStatusEnum.COMPLETE.getValue();
        }
      }
    }
    return ProcessInstanceStatusEnum.NOTSTART.getValue();
  }

  @Override
  public HistoricProcessInstance getHistoricProcessInstanceByBusinessKeyAndTenantId(String businessKey, String tenantId) {
    if (StringUtils.isBlank(businessKey)) {
      return null;
    }
    List<HistoricProcessInstance> historicProcessInstances = historyService.createHistoricProcessInstanceQuery()
        .processInstanceTenantId(tenantId).processInstanceBusinessKey(businessKey).orderByProcessInstanceEndTime()
        .desc().list();
    if (!historicProcessInstances.isEmpty()) {
      return historicProcessInstances.get(0);
    }
    return null;
  }

  @Override
  public ProcessDefinition getProcessDefinitionByProcessDefinitionKey(String processdefinitionId, String siteCode) {
    if (StringUtils.isBlank(processdefinitionId)) {
      return null;
    }
    ProcessDefinitionQuery pquery = repositoryService.createProcessDefinitionQuery();
    pquery = pquery.processDefinitionId(processdefinitionId).processDefinitionTenantId(siteCode);
    return pquery.singleResult();
  }

}
